#include "grpcserver.h"
#include <functional>
#include <fstream>

#include <QDebug>
#include <grpcpp/security/server_credentials.h>

std::unique_ptr<GrpcServer> g_pGrpcServer = nullptr;
GrpcServer *GrpcServer::instance()
{
    static GrpcServer server;
    return &server;
}

GrpcServer::~GrpcServer()
{
    m_server->Shutdown();
    if(m_thread.joinable())
        m_thread.join();
}

GrpcServer::GrpcServer()
{

}

void GrpcServer::RegisterService(std::shared_ptr<grpc::Service> service)
{
    m_listService.push_back(service);
}

void GrpcServer::StartGrpcServer(std::string ip, uint16_t port)
{
    m_ip = ip;
    m_port = port;
    m_thread = std::thread(std::bind(&GrpcServer::serverWait, this));
}


void GrpcServer::serverWait()
{
    std::string server_address = absl::StrFormat("%s:%d", m_ip, m_port);

    grpc::EnableDefaultHealthCheckService(true);
    grpc::reflection::InitProtoReflectionServerBuilderPlugin();


    auto  ReadFile = [](const std::string& filename) {
        std::ifstream file(filename);
        if (!file.is_open()) {
            throw std::runtime_error("Unable to open file: " + filename);
        }
        return std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    };

/*
    std::string server_cert = ReadFile("./server.crt");
    std::string server_key = ReadFile("./server.key");
    std::string ca_cert = "";

    // 设置服务器证书
    grpc::SslServerCredentialsOptions::PemKeyCertPair key_cert_pair;
    key_cert_pair.private_key = server_key;
    key_cert_pair.cert_chain = server_cert;

    grpc::SslServerCredentialsOptions ssl_opts;
    ssl_opts.pem_key_cert_pairs.push_back(key_cert_pair);
    ssl_opts.pem_root_certs = ca_cert;

    // 创建服务器凭证
    auto server_creds = grpc::SslServerCredentials(ssl_opts);
*/

    ServerBuilder builder;
    // Listen on the given address without any authentication mechanism.
    //builder.AddListeningPort(server_address, server_creds);

    builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
    // Register "service" as the instance through which we'll communicate with
    // clients. In this case it corresponds to an *synchronous* service.
    for(auto service : m_listService)
    {
        builder.RegisterService(service.get());
    }
    // Finally assemble the server.
    m_server = builder.BuildAndStart();
    qCritical() << "Server listening on " << server_address.c_str();
    // Wait for the server to shutdown. Note that some other thread must be
    // responsible for shutting down the server for this call to ever return.
    m_server->Wait();
}
